import { v2, Vec2 } from "cc";

/**
*copyright(c)2017-2020厦门风领科技有限公司
* http://www.fenglinghudong.com/
*
*随机数工具
*甘代诗
* 2021-12-21 14:22:07
*/
export class RandomUtil {
    /**
     * 根据权重,计算随机内容
     * @param weightArr 
     * @param totalWeight 权重
     * @returns 
     */
    public static getWeightRandIndex(weightArr: [], totalWeight: number) {
        let randWeight: number = Math.floor(Math.random() * totalWeight);
        let sum: number = 0;
        for (var weightIndex: number = 0; weightIndex < weightArr.length; weightIndex++) {
            sum += weightArr[weightIndex];
            if (randWeight < sum) {
                break;
            }
        }
        return weightIndex;
    }

    /**
     * 从权重数组中,计算随机数
     * @param weights 权重数组
     */
    public static getRandomByWeights(weights: number[]) {
        let totalWeight = 0;
        for (let i = 0; i < weights.length; i++) {
            totalWeight += weights[i];
        }
        let r: number = Math.random();
        let rr: number = r * (totalWeight + 1);
        let rand = Math.floor(rr);
        let randIndex = 0;
        let left = rand;
        for (let i = 0; i < weights.length; i++) {
            left -= weights[i];
            if (left <= 0) {
                randIndex = i;
                break;
            }
        }
        return randIndex;
    }

    /**
     * 从n个数中获取m个随机数
     * @param {Number} n   总数
     * @param {Number} m    获取数
     * @returns {Array} array   获取数列
     */
    public static getRandomNFromM(n: number, m: number) {
        let array: any[] = [];
        let intRd: number = 0;
        let count: number = 0;
        while (count < m) {
            if (count >= n + 1) {
                break;
            }
            intRd = this.randomInteger(0, n);
            var flag = 0;
            for (var i = 0; i < count; i++) {
                if (array[i] === intRd) {
                    flag = 1;
                    break;
                }
            }
            if (flag === 0) {
                array[count] = intRd;
                count++;
            }
        }
        return array;
    }
    /**
     * 获取随机整数
     * @param {Number} min 最小值
     * @param {Number} max 最大值
     * @returns 
     */
    public static randomInteger(min: number, max: number) {
        let r: number = Math.random();
        let rr: number = r * (max - min + 1) + min;
        return Math.floor(rr);
    }

    /**
     * 获得一个值的概率
     * @param value 
     * @returns 
     */
    public static probability(value: number) {
        return Math.random() < value;
    }

    /**
     * 随机一个bool值
     */
    static randomBool() {
        let result = 0;
        if (this.randomInteger(1, 10) > 5) {
            result = 1;
        }
        return !!result;
    }

    /**
     * 随机一个，取值区间[min, max]
     * @param min 最小值
     * @param max 最大值
     */
    static randomFloat(min, max) {
        if (min > max) {
            let temp = min;
            min = max;
            max = temp;
        }
        return Math.random() * (max - min) + min;
    }

    /**
     * 获取给定范围内随机值
     * @param num 0-n的n的具体数值
     * @param isIncludeMinus 是否包含负数
     * @returns 
     */
    public static getRandomRange(num: number, isIncludeMinus?: boolean) {
        if (isIncludeMinus) {
            return (Math.random() > 0.5 ? 1 : -1) * Math.random() * num;
        }
        return Math.random() * num;
    }

    /**
     * 随机返回一个数组中的值
     * @param array 需要取值的数组
     */
    static arrayRandomValue(array) {
        if (array.length <= 0) return [];
        let index = this.randomInteger(0, array.length - 1);
        return array[index];
    }

    /**
     * 随机返回多个个数组中的值
     * @param array 需要取值的数组
     */
    static arrayRandomValueByNum(array, number) {
        if (array.length <= number) return array;
        let nrwArray = this.deepClone_SlapKing_(array);
        nrwArray = this.shuffle(nrwArray);
        return nrwArray.slice(0, number);
    }

    /**随机概率 */
    public static getRandomByRatio(value: number[]): number {
        let info = [];
        value.forEach((value, index) => {
            info.push(Number(value));
        });
        let random = Math.random();
        let newValue: number[][] = [[0, info[0], 0]];
        let curValue = info[0];
        for (let i = 1; i < info.length - 1; i++) {
            newValue.push([curValue, curValue + info[i], i]);
            curValue += info[i];
        }
        for (let k = 0; k < newValue.length; k++) {
            if (random >= newValue[k][0] && random < newValue[k][1]) {
                return newValue[k][2];
            }
        }
        return info.length - 1;
    }

    /**随机求数组概率区间 下标 */
    public static sectionIndex(values: Array<number>): number {
        let newArr = [];
        let sub = 0;
        let lastNum = 0;
        for (let i = 0; i < values.length; i++) {
            sub += values[i];
        }
        for (let i = 0; i < values.length; i++) {
            newArr.push([lastNum, lastNum + values[i] / sub]);
            lastNum += values[i] / sub;
        }
        let random = Math.random();
        for (let index = newArr.length - 1; index >= 0; index--) {
            if (random > newArr[index][0] && random <= newArr[index][1]) {
                return index;
            }
        }
        return 0;
    }

    /**数据的深度拷贝 */
    static deepClone_SlapKing_(data: any) {
        if (!data || !(data instanceof Object) || (typeof data == "function")) {
            return data;
        }
        var constructor = data.constructor;
        var result = new constructor();
        for (var key in data) {
            if (data.hasOwnProperty(key)) {
                result[key] = this.deepClone_SlapKing_(data[key]);
            }
        }
        return result;
    }
    /**
     * 数组洗牌
     * @param arr 数组
     */
    static shuffle(arr: Array<any>): Array<any> {
        for (var i = arr.length - 1; i >= 0; i--) {
            var randomIndex = Math.floor(Math.random() * (i + 1));
            var itemAtIndex = arr[randomIndex];
            arr[randomIndex] = arr[i];
            arr[i] = itemAtIndex;
        }
        return arr;
    }

    /**
     * 随机扇形上的点
     * @param x 坐标x
     * @param y 坐标y
     * @param radius 半径
     * @param startAngle 初始角度
     * @param endAngle 结束角度
     */
    public static getRandomXYInfan(x: number, y: number, radius: number, startAngle: number, endAngle: number): Vec2 {
        var angle: number = startAngle + Math.random() * (endAngle - startAngle);
        var newPoint = v2();
        newPoint.x = x + radius * Math.cos(angle);
        newPoint.y = y - radius * Math.sin(angle);
        return newPoint;
    }

    /**求概率 */
    public static dichotomy(arr, num, idx) {
        if (idx > 0 && idx + 1 < arr.length) {
            if (num >= arr[idx - 1] && num <= arr[idx]) {
                return idx - 1;
            } else if (num >= arr[idx] && num <= arr[idx + 1]) {
                return idx;
            } else if (num < arr[idx - 1]) {
                let min = idx <= Math.floor(arr.length / 2) ? 0 : Math.floor(arr.length / 2);
                return this.dichotomy(arr, num, Math.floor((idx + min) / 2));
            } else if (num > arr[idx + 1]) {
                let max = idx < Math.floor(arr.length / 2) ? Math.floor(arr.length / 2) : arr.length;
                return this.dichotomy(arr, num, Math.floor((idx + max) / 2));
            }
        } else {
            return -1;
        }
    }
}